﻿using Microsoft.Win32;
using Microsoft.Xrm.Client;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Query;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace FGrubert.CrmQueueMonitor.WinForms
{
    public partial class FrmSettings : Form
    {
        /// <summary>
        /// Store the settings
        /// </summary>
        private Properties.Settings settings = Properties.Settings.PermanentDefault;
        /// <summary>
        /// The list of the queues
        /// </summary>
        private SortableBindingList<QueueConfig> _queues = new SortableBindingList<QueueConfig>();

        public FrmSettings()
        {
            InitializeComponent();
        }

        private void FrmSettings_Load(object sender, EventArgs e)
        {
            txtCrmUrl.Text = settings.CrmUrl;
            radAuthenticationIntegrated.Checked = settings.UseIntegratedAuthentication;
            radAuthenticationCustom.Checked = !settings.UseIntegratedAuthentication;
            txtDomain.Text = settings.Domain;
            txtUsername.Text = settings.Username;
            txtPassword.Text = settings.Password;
            chkAutostart.Checked = settings.Autostart;
            numOpacity.Value = settings.Opacity;
            cmbStatusCalculation.SelectedIndex = (int)settings.StatusCalculationMode;
            chkEnableAutoscale.Checked = settings.EnableAutoscale;

            dgvQueues.AutoGenerateColumns = false;
            dgvQueues.DataSource = _queues;

            Connect(true);
        }

        /// <summary>
        /// Initializes the connection to CRM
        /// </summary>
        /// <param name="suppressMessage">If set to true: No Message will be shown if an error occurs</param>
        private void Connect(bool suppressMessage)
        {
            try
            {
                SetEnabledState(true);
                _queues.Clear();

                List<QueueConfig> queueList = new List<QueueConfig>();

                QueueBase[] queueConfigs = settings.QueueConfigs;

                IOrganizationService orgService = CrmConnector.GetCrmConnection(new Uri(txtCrmUrl.Text), radAuthenticationIntegrated.Checked, txtDomain.Text, txtUsername.Text, txtPassword.Text);

                QueryExpression query = new QueryExpression("queue");
                query.ColumnSet = new ColumnSet("name", "queueid");

                FilterExpression filter = new FilterExpression();
                filter.AddCondition("statecode", ConditionOperator.Equal, 0);
                query.Criteria = filter;

                query.AddOrder("name", OrderType.Ascending);

                EntityCollection entities = orgService.RetrieveMultiple(query);

                foreach (Entity entity in entities.Entities)
                {
                    QueueConfig queue = new QueueConfig();
                    queue.QueueId = entity.Id;
                    queue.Name = entity.GetAttributeValue<string>("name");

                    QueueBase storedConfig = queueConfigs.FirstOrDefault(q => q.QueueId == entity.Id);
                    if (storedConfig != null)
                    {
                        queue.Selected = true;
                        queue.HoursToYellow = storedConfig.HoursToYellow;
                        queue.HoursToRed = storedConfig.HoursToRed;
                    }

                    queueList.Add(queue);
                }

                _queues.AddRange(queueList.OrderBy(q => q, new QueueConfigDefaultComparer()));
                // For some reasons there is an error in the Data Grid View so it throws an error when scrolling if we do not call this after updating
                dgvQueues.PerformLayout();
            }
            catch (FileNotFoundException error)
            {
                if (error.Message.Contains("Microsoft.IdentityModel"))
                {
                    string message = "Windows Identity Foundation is not installed, so the connection to Dynamics CRM can not be established. Please install and enable Windows Identity Foundation before you continue.";
                    if (Environment.OSVersion.Platform == PlatformID.Win32NT)
                    {
                        if (Environment.OSVersion.Version.Major > 6 || (Environment.OSVersion.Version.Major == 6 && Environment.OSVersion.Version.Major >= 2))
                        {
                            message += Environment.NewLine + "To enable Windows Identity Foundation for Windows 8 and following versions:"
                                + Environment.NewLine + "Open 'Programs and Features' in the Control Panel"
                                + Environment.NewLine + "Select 'Add or change Windows Features'"
                                + Environment.NewLine + "Enable 'Windows Identity Foundation X.Y'";
                            MessageBox.Show(this, message, "Required Component missing", MessageBoxButtons.OK, MessageBoxIcon.Error);
                        }
                        else
                        {
                            message += Environment.NewLine + "To enable Windows Identity Foundation for Windows Vista or Windows 7:"
                                + Environment.NewLine + "Go to http://www.microsoft.com/download/details.aspx?id=17331"
                                + Environment.NewLine + "Download and install the appropriate package for your system."
                                + Environment.NewLine + "Windows Vista = 6.0; Windows 7 = 6.1"
                                + Environment.NewLine + "Do you want to open the Download Website now?";
                            DialogResult result = MessageBox.Show(this, message, "Required Component missing", MessageBoxButtons.YesNo, MessageBoxIcon.Error);
                            if (result == System.Windows.Forms.DialogResult.Yes)
                            {
                                System.Diagnostics.Process.Start("http://www.microsoft.com/download/details.aspx?id=17331");
                            }
                        }
                    }
                    else
                    {
                        MessageBox.Show(this, message, "Required Component missing", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    }
                }
                else if (!suppressMessage)
                {
                    MessageBox.Show(this, error.Message, "Could not connect to CRM", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
            }
            catch (Exception error)
            {
                if (!suppressMessage)
                {
                    MessageBox.Show(this, error.Message, "Could not connect to CRM", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
            }
            SetEnabledState(false);
        }

        /// <summary>
        /// Save the current settings
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnOK_Click(object sender, EventArgs e)
        {
            settings.CrmUrl = txtCrmUrl.Text;
            settings.UseIntegratedAuthentication = radAuthenticationIntegrated.Checked;
            settings.Domain = txtDomain.Text;
            settings.Username = txtUsername.Text;
            settings.Password = txtPassword.Text;
            settings.Autostart = chkAutostart.Checked;
            settings.Opacity = (int)numOpacity.Value;
            settings.StatusCalculationMode = (StatusCalculationMode)cmbStatusCalculation.SelectedIndex;
            settings.EnableAutoscale = chkEnableAutoscale.Checked;

            settings.QueueConfigs = _queues.Where(q => q.Selected).ToArray();

            settings.SavePermanent();

            try
            {
                RegistryKey regKey = Registry.CurrentUser.OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Run", true);
                if (!settings.Autostart)
                {
                    regKey.DeleteValue("CRM Queue Monitor", false);
                }
                else
                {
                    string executable = Assembly.GetEntryAssembly().Location;
                    regKey.SetValue("CRM Queue Monitor", executable, RegistryValueKind.String);
                }
            }
            catch { }
        }

        /// <summary>
        /// Try to connect to crm
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnTestConnection_Click(object sender, EventArgs e)
        {
            Connect(false);
        }

        /// <summary>
        /// Set the enabled state of the components
        /// </summary>
        /// <param name="disabled">If true: set everything to disabled, else reset to default state</param>
        private void SetEnabledState(bool disabled)
        {
            txtCrmUrl.Enabled = !disabled;
            radAuthenticationCustom.Enabled = !disabled;
            radAuthenticationIntegrated.Enabled = !disabled;
            txtDomain.Enabled = !disabled && radAuthenticationCustom.Checked;
            txtUsername.Enabled = !disabled && radAuthenticationCustom.Checked;
            txtPassword.Enabled = !disabled && radAuthenticationCustom.Checked;

            chkAutostart.Enabled = !disabled;
            numOpacity.Enabled = !disabled;
            cmbStatusCalculation.Enabled = !disabled;
            chkEnableAutoscale.Enabled = !disabled;

            btnTestConnection.Enabled = !disabled && !string.IsNullOrEmpty(txtCrmUrl.Text);
            dgvQueues.Enabled = !disabled && !string.IsNullOrEmpty(txtCrmUrl.Text);
            btnOK.Enabled = !disabled && !string.IsNullOrEmpty(txtCrmUrl.Text);
        }

        /// <summary>
        /// Reset the enabled state
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void radAuthenticationIntegrated_CheckedChanged(object sender, EventArgs e)
        {
            SetEnabledState(false);
        }

        /// <summary>
        /// Reset the enabled state
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void txtCrmUrl_TextChanged(object sender, EventArgs e)
        {
            SetEnabledState(false);
        }

        /// <summary>
        /// An error occured during data validation
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void dgvQueues_DataError(object sender, DataGridViewDataErrorEventArgs e)
        {
            MessageBox.Show(this, e.Exception.Message, "Error during data validation", MessageBoxButtons.OK, MessageBoxIcon.Error);
        }
    }
}
